Unit NTFS;

INTERFACE
uses dos, crt;

const
     MAX_FILES      = 2000;
     MAX_NAME       = 32;

     TYPE_FAT12          = $01;
     TYPE_FAT16          = $04;
     TYPE_BIG_FAT16      = $06;
     TYPE_NTFS           = $07;
     TYPE_EXTEND         = $05;
     TYPE_FAT32          = $0B;
     TYPE_FAT32_INT13    = $0C;
     TYPE_BIG_FAT16_INT13= $0E;
     TYPE_EXTEND_INT13   = $0F;

     DISKNUM             = $80;
     FILE_SIGNATURE      = $454C4946;{FILE}
     NTFS_SIGNATURE      = $5346544E;{NTFS}
     INDX_SIGNATURE      = $58444E49;{INDX}
     {------------------}
     FILENAME_ID         = $30;
     VOLUME_NAME_ID      = $60;
     DATA_ID             = $80;
     INDEX_ROOT_ID       = $90;
     INDEX_ALLOC_ID      = $A0;
     BITMAP_ID           = $B0;
     {--------------------}
     fAttrDir            = $10000000;
{-------------------------------------------------------------------------}
Type
    NameString = string[MAX_NAME];
    DiskPacket=Record
        size:     byte;
        reserve:  byte;
        wBlocks:  word;
        offset:      word;
        segment:      word;
        BlockLo:  longint;
        BlockHi:  longint;
    End;
    {---------------------------}
    PClusterRun = ^ClusterRun;
    {bieu dien mot mach cluster, tinh theo dia chi tuong doi}
    ClusterRun = record
        start  :longint;
        len    :longint;
        next   :PClusterRun;
    end;

    DiskParam = Record
        Volume        :NameString;
        DiskNum       :byte;
        DiskType      :byte;
        SecPerClus    :byte;
        FileRecSize   :word;{in bytes}
        IndxRecSize   :word;
        RelativeSec   :longint;{Dia chi tuyet doi tu dau dia}
        MFTClusStart  :longint;{dia chi clusters bat dau cua MFT}
        TotalSec      :longint;
        pClusRun      :PClusterRun;
    End;
    DiskList = Array[1..10] of DiskParam;
    {---------------------------}
    PFolderItem = ^FolderItem;
    FolderItem = Record
        name:NameString;
        fRecNum:longint; {File Record number}
        fParentNum: longint;
        realsizeLo:longint; {kich thuoc thuc}
{       realsizeHi:longint;}
        allocsizeLo:longint;{kich thuoc da cap phat}
{       allocsizeHi:longint;}
        Flags:longint;
        next:PFolderItem;
        prev:PFolderItem;
    End;
    SectorType = array[0..511] of byte;
    FileRecType = array[0..1023] of byte;
{-------------------------------------------------------------------------}
{procedure}
procedure freelstPFI(var pHead:PFolderItem);
procedure GetPartitionList(var dlst:DiskList; var n:byte);
procedure GetMFTClusRun(BootSec:longint; var dp: DiskParam);
procedure GetFolderItems(fRecNum:longint; var fi:PFolderItem; dp:DiskParam);
procedure ErrMsg(msg:string);
{==========================================================================}
IMPLEMENTATION

procedure ErrMsg(msg:string);
begin
     Textcolor(7);TextBackground(0);
     clrscr;
     writeln(msg);
     halt;
end;
{-----------------------------------------------------------------------}
{chuyen chuoi unicode dai len tai src sang chuoi ansi dest}
procedure Unicode2Ansi(var src; var dest:NameString; len:word);
var s, o, i:word;
begin
     s := seg(src); o := ofs(src);
     if len > MAX_NAME then len := MAX_NAME;
     for i := 1 to len do
     begin
          dest[i] := char(mem[s : o + 2 * i - 2]);
     end;
     dest[0] := char(len);
end;
{-----------------------------------------------------------------------}
Procedure ReadSec(disk:byte; StartSec:longint; SecLen:byte; var buf; var err:boolean);
var reg:Registers;
    addr:DiskPacket;
Begin
     with addr do
     begin
          size := $10;
          wBlocks := SecLen;
          offset := Ofs(buf);
          segment := Seg(buf);
          BlockHi := 0;
          BlockLo := StartSec;
     end;
     with reg do
     begin
          ah := $42;
          dl := disk;
          ds := Seg(addr);
          si := Ofs(addr);
     end;
     Intr($13, reg);
     if (reg.flags and fCarry = 1) then
        err := true
     else
        err := false;
End;
{-----------------------------------------------------------------------}
procedure GetNTFSInfo(var dp :DiskParam);
var p : pointer;
    i : byte;
    s, o, offset, len : word;
    err   : boolean;
    Sec   : longint;
Begin
     if dp.DiskType <> TYPE_NTFS then exit;
     {doc BS}
     getmem(p, 1024);
     s := seg(p^); o := ofs(p^);
     ReadSec(dp.DiskNum, dp.RelativeSec, 1, p^, err);

     if (meml[s : o + 3] <> NTFS_SIGNATURE) then
     begin
          freemem(p, dp.FileRecSize);
          exit;
     end;
     with dp do
     begin
          SecPerClus  := mem[s : o + $0D];
          FileRecSize := 1024;{(meml[s : o + $40] * SecPerClus) shl 9;}
          IndxRecSize := (meml[s : o + $44] * SecPerClus) shl 9;
          MFTClusStart:= meml[s : o + $30];
     end;
     {lay volume label}
     {Vi $Volume la co stt = 3 -> can cong 6 sector}
     Sec := dp.RelativeSec + dp.SecPerClus * dp.MFTClusStart + 6;
     ReadSec(dp.DiskNum, Sec, 2, p^, err);{Doc $Volume}

     if (meml[s : o] <> FILE_SIGNATURE) then
     begin
          freemem(p, dp.FileRecSize);
          exit;
     end;
     {Tim thuoc tinh $VOLUME_NAME}
     offset := memw[s : o + $14];{Thuong co gia tri $30}
     while (meml[s : o + offset] <> VOLUME_NAME_ID) and (offset < dp.FileRecSize) do
     begin
          offset := offset + meml[s : o + offset + 4];
     end;
     if (offset < dp.FileRecSize) then
     begin
          len := meml[s : o + offset + $10] div 2;
          Unicode2Ansi(mem[s : o + offset + $18], dp.Volume, len);
     end;
     freemem(p, dp.FileRecSize);
End;
{-----------------------------------------------------------------------}
procedure GetVolumeLabel(var dp: DiskParam);
var p:^SectorType;
    offset, i:byte;
    err:boolean;
begin
     new(p);
     ReadSec(dp.DiskNum, dp.RelativeSec, 1, p^, err);
     case dp.DiskType of
          TYPE_FAT16, TYPE_BIG_FAT16 :          {FAT16}
               offset := $2B;
          TYPE_FAT32:                           {FAT32}
               offset := $47;
          else
               begin dispose(p); exit; end;
     end;
     move(p^[offset],dp.volume[1], 11);
     i := 1;
     while ((dp.volume[i] <> #0) and (i < 11)) do inc(i);
     dp.volume[0] := chr(i-1);
     dispose(p);
end;
{-----------------------------------------------------------------------}
{Quet bang phan vung trong co MBR tai Sector Sec}
{SecExtStart: sector dau extended partition}
Procedure ScanExt(physical_drive: byte; Sec, SecExtStart:longint; var dlst:DiskList; var n:byte);
var buf:array[0..511] of byte;
    err:boolean;
    i  :integer;
    addr, MBSec: longint;
    sbuf, obuf : word;
Begin
     sbuf := seg(buf); obuf := ofs(buf);
     ReadSec(physical_drive, Sec, 1, buf, err);
     if err then exit;
     addr := $1BE;
     for i := 1 to 4 do
     begin
          case buf[addr + 4] of {Kiem tra System ID}
               TYPE_FAT16, TYPE_BIG_FAT16, TYPE_BIG_FAT16_INT13,  {FAT16}
               TYPE_FAT32, TYPE_FAT32_INT13,                      {FAT32}
               TYPE_NTFS:                                         {NTFS}
                    begin
                         inc(n);
                         with dlst[n] do
                         begin
                              DiskNum  := physical_drive;
                              DiskType := buf[addr + 4];
                              RelativeSec := MemL[sbuf : obuf + addr + 8] + Sec;
                              TotalSec := MemL[sbuf : obuf + addr + $0C];
                         end;
                         if (buf[addr + 4] = TYPE_NTFS) then
                            GetNTFSInfo(dlst[n])
                         else
                            GetVolumeLabel(dlst[n]);{Lay nhan dia}
                    end;
               $05, $0F:{Extend partition}
                    begin
                         MBSec := SecExtStart + MemL[sbuf : obuf + addr + 8];
                         if Sec = 0 then {Day la MBR}
                            ScanExt(physical_drive, MBSec, meml[sbuf : obuf + addr + 8], dlst, n)
                         else
                            ScanExt(physical_drive ,MBSec, SecExtStart, dlst, n);
                    end;
          end;
          inc(addr, $10);
     end;
End;
{-----------------------------------------------------------------------}
Procedure GetPartitionList(var dlst:DiskList; var n:byte);
var physical_drive : byte;
Begin
     {Doc MBR, lay ra danh sach cac phan vung}
     n := 0;
     for physical_drive := $80 to $83 do
     begin
          ScanExt(physical_drive, 0, 0, dlst, n);
     end;
End;
{-----------------------------------------------------------------------}
procedure freelstPCR(var pHead:PClusterRun);
var p, pFree : PClusterRun;
begin
     if pHead = nil then exit;

     p := pHead^.next;
     while (p <> nil) do
     begin
          pFree := p;
          p := p^.next;
          dispose(pFree);
     end;
     dispose(pHead);
     pHead := nil;
end;
{xoa ds lk dang PFolderItem}
procedure freelstPFI(var pHead:PFolderItem);
var p, pFree : PFolderItem;
begin
     if pHead = nil then exit;

     p := pHead^.next;
     while (p <> nil) do
     begin
          pFree := p;
          p := p^.next;
          dispose(pFree);
     end;
     dispose(pHead);
     pHead := nil;
end;
{-----------------------------------------------------------------------}
{Doc count clusters bat dau tai vcn (tinh theo VCN cua mach pcl)}
{Toi da chi doc 64K}
procedure ReadVCN(pcl:PClusterRun; dp:DiskParam; var buf; vcn, Count: word; var result:word);
var s, o: word;
    SecLen : word;
    p    : PClusterRun;
    lcn, SecStart : longint;
    found, err : boolean;
begin
     s := seg(buf); o := ofs(buf);
     p := pcl^.next;
     lcn := 0;
     found := false;
     while (vcn >= 0) and (p <> nil) and (not found)do {tim lcn bat dau khoi}
     begin
          lcn := lcn + p^.start;
          if vcn >= p^.len then
             begin
                  vcn := vcn - p^.len;
                  p := p^.next;
             end
          else    {da tim thay lcn bat dau}
             begin
                  found := true;
                  lcn := lcn + vcn;
             end;
     end;
     result := 0;
     while true do
     begin
          {can doc min (p^.len, Count), bat dau tu lcn}
          SecStart := dp.RelativeSec + lcn * dp.SecPerClus;
          if (vcn + Count <= p^.len ) then
             begin
                  SecLen := Count * dp.SecPerClus;
                  ReadSec(dp.DiskNum, SecStart, SecLen, mem[s : o], err);
                  inc (result, count);
                  exit;{da doc du}
             end
          else
             begin {doc mot phan, sau do tim tiep}
                  SecLen := (p^.len - vcn) * dp.SecPerClus;
                  ReadSec(dp.DiskNum, SecStart, SecLen, mem[s : o], err);
                  o := o + (SecLen shl 9);
                  dec (Count, p^.len - vcn);
                  inc (result, p^.len - vcn);
                  dec (lcn, vcn);{chinh lai}
                  vcn := 0;
             end;
          if (p <> nil) then p := p^.next
                        else exit;{doc thieu}
          inc (lcn, p^.start);{sang mach tiep theo}
     end;
end;
{-----------------------------------------------------------------------}
{chuyen mot data run thanh cluster bat dau va do rong}
{Dau vao:
     dia chi tro toi data run
Dau ra:
    - start: Cluster bat dau
    - len: do dai mach cluster
    - bytewidth: so byte can de luu mach data run vua giai ma
}
procedure DecodeDataRun(var p;var start, len:longint; var bytewidth: byte);
var sp, op : word;
    header, len_size, i, j : byte;
    b, mask, start_size:longint;
begin
     sp := seg(p); op := ofs (p);
     header := mem[sp : op]; {lay header cua mach}
     len_size := header and $0F;
     start_size := header shr 4;
     bytewidth := len_size + start_size + 1;
     {lay cluster bat dau mach va do dai mach}
     len := 0;
     for j := 1 to len_size do
     begin
          inc(op);
          b := mem[sp : op];
          len := (b shl (8*(j-1))) or len;
     end;
     start := 0;
     for j := 1 to start_size do
     begin
          inc(op);
          b := mem[sp : op];
          start := (b shl ((j-1) shl 3)) or start;
     end;
     {neu bit cao nhat cua start bang 1->chuyen thanh so am}
     {lay bit cao nhat, start_size phai la longint de phep dich trai khong bi tran}
     mask := 1 shl (start_size shl 3 - 1);
     if (start and mask <> 0) then {day la so am}
     begin
          start := -(mask shl 1 - start);
     end;
end;
{-----------------------------------------------------------------}
{lay mach cluster, dua vao pclus}
procedure GetClusRuns(var buf; size:word; var pclus: PClusterRun);
var sbuf, obuf, offset: word;
    run_start, run_len: longint;
    bw : byte;
    p, pnew: PClusterRun;

begin
     sbuf := seg(buf); obuf := ofs(buf);
     offset := 0;
     if (pclus = nil) then
     begin
        new(pclus);
        pclus^.next := nil;
     end;
     p := pclus;

     while (mem[sbuf : obuf + offset] <> 0) and (offset <= size) do
     begin

          DecodeDataRun(mem[sbuf : obuf + offset], run_start, run_len, bw);
          inc (offset, bw);
          {them mot mach vao duoi}
          new(pnew);
          pnew^.start := run_start;
          pnew^.len   := run_len;
          pnew^.next  := nil;
          p^.next := pnew;
          p := pnew;
     end;
end;
{-----------------------------------------------------------------}
{Lay danh sach cac mach cluster trong MFT}
{Dau vao:Boot sector cua NTFS}
{Dau ra: danh sach cac mach cluster (ds lk co nut gia o dau)}
procedure GetMFTClusRun(BootSec:longint; var dp: DiskParam);
var buf:^byte;
    err:boolean;
    sbuf, obuf, offset :word;
    Sec, run_len, run_start, size :longint;
    run_header, len_size, start_size, bw :byte;
    i, j:integer;
Begin
     if dp.DiskType <> TYPE_NTFS then exit;
     getmem(buf, dp.FileRecSize);
     sbuf := seg(buf^); obuf := ofs(buf^);
     {Lay dia chi sector tro toi MFT}
{     Sec := dp.RelativeSec + dp.SecPerClus * MemL[seg(buf^):ofs(buf^) + $30];

     {Lay dia chi sector tro toi MFT}
     Sec := dp.RelativeSec + dp.SecPerClus * dp.MFTClusStart;
     ReadSec(dp.DiskNum, Sec, 2, buf^, err);{Doc $MFT}
     if (err) then ErrMsg('Disk read error!');
     {kiem tra xem OEM ID  co phai la NTFS khong}
     if (meml[sbuf : obuf] <> FILE_SIGNATURE) then
          ErrMsg('Error! Cound not find $MFT.');
     {Tim thuoc tinh $DATA ($80)}
     offset := $30;
     while (MemL[sbuf : obuf + offset] <> DATA_ID) and (offset < dp.FileRecSize) do
     begin
          offset := offset + meml[sbuf : obuf + offset + 4];
     end;
     if (meml[sbuf : obuf + offset] <> DATA_ID) then
              ErrMsg('Error! Could not find $DATA in $MFT');
     {doc cac mach cluster}

     size := meml[sbuf : obuf + offset + 4];
     inc(offset, $40); {chuyen toi data run}
     GetClusRuns(mem[sbuf : obuf + offset], size, dp.pClusRun);
     freemem(buf, dp.FileRecSize);
End;
{-----------------------------------------------------------------------}
{Chuyen tu File Record number trong bang MFT
sang sector tuyet doi tinh tu dau phan vung}
{Chu y: stt tinh tu 0}
function GetSecNum(dp:DiskParam; frecnum:longint):longint;
var p: PClusterRun;
    StartSec, sec, SecPerFileRec: longint;
    found: boolean;

begin
     p := dp.pclusrun;
     if (p = nil) then exit;
     p := p^.next;
     StartSec := 0;
     found := false;
     SecPerFileRec := dp.FileRecSize shr 9;{mac dinh sector size = 512}
     sec := frecnum * SecPerFileRec;

     while (sec >= 0) and (p <> nil) and (not found)do
     begin
          StartSec := StartSec + p^.start * dp.SecPerClus;
          if (sec > p^.len * dp.SecPerClus) then
             begin
                  sec := sec - p^.len * dp.SecPerClus;
                  p := p^.next;
             end
          else {da tim thay, tra ve}
             begin
                  GetSecNum := StartSec + sec;
                  found := true;
             end;

     end;
     if not found then GetSecNum := -1;
end;
{-----------------------------------------------------------------------}
{phan tich cau truc cua 1 index entry, tra ve thong tin cua index entry do}
procedure ParseIdxEntry(var buf; var fi: FolderItem);
var sbuf, obuf, ofs_fn:word;
    len_fn: word;
begin
     sbuf := seg(buf); obuf := ofs(buf);
     with fi do
     begin
          {copy file name}
          ofs_fn := $52;{memw[sbuf : obuf + $0A] -> co luc bi sai, <> $52}
          len_fn := mem [sbuf : obuf + $50];
          Unicode2Ansi(mem[sbuf : obuf + ofs_fn], name, len_fn);

          fRecNum := meml[sbuf : obuf];
          fParentNum := meml[sbuf : obuf + $10];
          realsizeLo := meml[sbuf : obuf + $40];
{          realsizeHi := meml[sbuf : obuf + $44];}
          allocsizeLo := meml[sbuf : obuf + $38];
{          allocsizeHi := meml[sbuf : obuf + $3C]; }
          Flags := meml[sbuf : obuf + $48];
          next := nil;
     end;
end;
{-----------------------------------------------------------------------}
{Phan tich cac index entries}
{Tra ve:
     lay ra cac file luu vao cuoi danh sach fi
     so luong entries lay duoc-->n}
procedure ParseIndexEntries(var buf; memlen : word;var fi:PFolderItem;var n:word);
var sbuf, obuf, offset: word;
    p, pnew: PFolderItem;
begin
     sbuf := seg(buf); obuf := ofs(buf);
     offset := 0;
     if (fi = nil) then
     begin
        new(fi);
        fillchar(fi^, sizeof(FolderItem), $FF);
        fi^.next := nil;
        fi^.prev := fi;
     end;
     p := fi;
     while p^.next <> nil do p := p^.next;   {cho p tro toi cuoi danh sach}

     while (memw[sbuf : obuf + offset + $0C] and $02 = 0)
           and (offset < memlen) do {khi index flag ko phai la cuoi cung}
     begin
          {doc tung index entry}
          inc(n);
          new(pnew);
          parseidxentry(mem[sbuf : obuf + offset], pnew^);
          {them vao danh sach}

          pnew^.prev := p;
          p^.next := pnew;
          p := pnew;
          inc (offset, memw[sbuf : obuf + offset + $08]); {chuyen den entry tiep}
     end;
end;
{-----------------------------------------------------------------------}
{Phan tich thuoc tinh $INDEX_ALLOCATION, doc Index Record,
lay ra danh sach cac index entry dua vao fi.
Dau vao:
    + buf: tro toi du lieu
Dau ra:
    + fi:danh sach cac file, thu muc con
}
procedure ParseIndexAllocAttr(var buf; var fi:PFolderItem; var dp:DiskParam);
var sbuf, obuf, maxfiles, n: word;
    vcnCount, clusRead, memlen, SecPerIndx, ClusPerIndx: word;
    start_clus, len, sec, size, offset : longint;
    bw : byte;
    p  : pointer;
    i, j, maxRec: integer;
    err: boolean;
    pclus, pclushead, pnew: PClusterRun;
Begin
     { $INDEX_ALLOC la thuoc tinh khong thuong tru}
     sbuf := seg(buf); obuf := ofs(buf);
     {sizeof(data_runs) = sizeof(attribute) - offset to data_runs}
     size := meml[sbuf : obuf + $04] - memw[sbuf : obuf + $20];
     {nhay qua standard header}
     obuf := obuf + memw[sbuf : obuf + $20];
     {lay danh sach cac cluster run}
     pclushead := nil;
     {--------------------}
     GetClusRuns(mem[sbuf : obuf], size, pclushead);
     pclus := pclushead^.next;
     vcnCount := 0;           {Tinh so clusters trong mach}
     while (pclus <> nil) do
     begin
          inc (vcnCount, pclus^.len);
          pclus := pclus^.next;
     end;
     SecPerIndx := (dp.IndxRecSize shr 9);
     ClusPerIndx := SecPerIndx div dp.SecPerClus;{kich thuoc Index Record, tinh theo cluster}

     maxRec := vcnCount div ClusPerIndx - 1; {STT IndexRec lon nhat}
     getmem(p, dp.IndxRecSize);
     sbuf := seg(p^); obuf := ofs(p^);

     maxfiles := 0;{so file trong thu muc}
     for i := 0 to maxRec do
     begin
          ReadVCN(pclushead, dp, p^,  ClusPerIndx * i, ClusPerIndx, clusRead);{doc Index Record thu i}
          {kiem tra xem co phai index record khong: INDX}
          if (meml[sbuf : obuf] <> $58444E49) then continue;
          {nhay toi cac index entries}
          offset := meml[sbuf : obuf + $18] + $18;
          {phan tich cac index entries}
          memlen := (clusRead * dp.SecPerClus) shl 9 - offset;{do dai vung nho duoc phep truy cap}
          ParseIndexEntries(mem[sbuf : obuf + offset], memlen, fi, maxfiles);
          if (maxfiles >= MAX_FILES) then break;
     end;

     freelstPCR(pclushead);
     freemem(p, dp.IndxRecSize);
End;
{------------------------------------}
{Phan tich thuoc tinh $INDEX_ROOT}
procedure ParseIndexRootAttr(var buf; var fi:PFolderItem; var dp:DiskParam);
var sbuf, obuf, ofsIndexRoot, n : word;
    indx_hdr_flag : byte;
    size : longint;
    memlen :word;
    offset : word;
Begin
     sbuf := seg(buf); obuf := ofs(buf);
     size := meml[sbuf : obuf + $04];{kich thuoc $INDEX_ROOT}

{     addr := addr + memw[sbuf : obuf + addr + $14];}
     { $INDEX_ROOT la thuoc tinh thuong tru--> tai 0x14 co chua offset toi index root}
     ofsIndexRoot := memw[sbuf : obuf + $14];
     indx_hdr_flag := mem[sbuf : obuf + ofsIndexRoot + $1C];
     if (indx_hdr_flag = 0) then  {bang 0x00 -> index_entries chua trong $INDEX_ROOT}
     begin
          memlen := size - $20 - (ofsIndexRoot - obuf);{kich thuoc vung index entries}
          { $20 = sizeof (index root) + sizeof(index header)}
          obuf := obuf + ofsIndexRoot + $20;{Tro den dau mang cac index entry}

          ParseIndexEntries(mem[sbuf : obuf], memlen, fi, n);{phan tich cac index entries}
     end
     else if (indx_hdr_flag = 1) then begin {truy xuat $INDEX_ALLOCATION}
          obuf := ofs(buf) + size;
          offset := 0;
          if (meml[sbuf : obuf] <> INDEX_ALLOC_ID) then
              ErrMsg('Error! Could not find $INDEX_ALLOCATION!');
          ParseIndexAllocAttr(mem[sbuf : obuf + offset], fi, dp);
     end;
End;
{-----------------------------------------------------------------------}
{Lay danh sach cac file nam  trong thu muc co File Record la fRecNum}
{Param:
       fRecNum: File Record number cua thu muc
       fi:Danh sach lien ket cac FolderItem;
       dp:Tham so o dia logic can doc
}
Procedure GetFolderItems(fRecNum:longint; var fi:PFolderItem; dp:DiskParam);
var buf: ^byte;
    err: boolean;
    sbuf, obuf, addr, size, ofs_attr :word;
    secnum, indexroot_size, indexroot_start:longint;
    indx_hdr_flag: byte;
Begin
     if (fi <> nil) then freelstPFI(fi);
     getmem(buf, dp.FileRecSize);
     sbuf := seg(buf^); obuf := ofs(buf^);
     {Doc File Record}
     secnum := dp.RelativeSec + GetSecNum(dp, fRecNum);{Sector tro toi File record}
     size   := dp.FileRecSize shr 9;{File Record size, tinh theo sector}
     ReadSec(dp.DiskNum, secnum, size, buf^, err);
     {------------------------------------}
     if (meml[sbuf : obuf] <> FILE_SIGNATURE) then
     begin
          freemem(buf, dp.FileRecSize);
          ErrMsg('Error! Invalid signature ''FILE''');
     end;
     {Tim thuoc tinh $FILE_NAME}
     addr := $30;
     while (MemL[sbuf : obuf + addr] <> FILENAME_ID) and (addr < dp.FileRecSize) do
     begin
          addr := addr + meml[sbuf : obuf + addr + 4];
     end;
     if (addr > dp.FileRecSize) then {not found}
        ErrMsg('Error! Could not find $FILE_NAME!');
     ofs_attr := memw[sbuf : obuf + addr + $14];{offset toi attribute}
     if (meml[sbuf : obuf + addr + ofs_attr + $38] and fAttrDir = 0) then{day khong phai la thu muc}
     begin
          exit;
     end;
     {Tim thuoc tinh $INDEX_ROOT($90)}
     while (MemL[sbuf : obuf + addr] <> INDEX_ROOT_ID) and (addr < dp.FileRecSize) do
     begin
          addr := addr + meml[sbuf : obuf + addr + 4];
     end;
     if (addr > dp.FileRecSize) then
        ErrMsg('Error! Could not find $INDEX_ROOT!');
     {addr tro toi dau $INDEX_ROOT}
     {------------------------------}
     {Phan tich $INDEX_ROOT}
     ParseIndexRootAttr(mem[sbuf : obuf + addr], fi, dp);

     {------------------------------}
     freemem(buf, dp.FileRecSize);
End;
{-----------------------------------------------------------------------}
END.
